package cn.com.rexen.ca;


import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.ejbca.core.model.AlgorithmConstants;
import org.ejbca.core.protocol.ws.client.gen.*;
import org.ejbca.core.protocol.ws.common.CertificateHelper;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;
import org.ejbca.util.CryptoProviderTools;
import org.ejbca.util.keystore.KeyTools;
import org.ejbca.util.provider.TLSProvider;

import javax.net.ssl.KeyManagerFactory;
import javax.security.auth.x500.X500Principal;
import javax.xml.namespace.QName;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

/**
 * 调用EJBCA WS接口.
 * Created by libo on 2014/6/16.
 */
public class CaWS {

    /* 解决 java.security.cert.CertificateException: No subject alternative names matching IP address 172.17.2.248 found
    172.17.2.248 换成自己的IP或机器名。
     */
    static {
        javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
                new javax.net.ssl.HostnameVerifier() {

                    public boolean verify(String hostname,
                                          javax.net.ssl.SSLSession sslSession) {
                        if (hostname.equals("172.17.2.248")) {
                            return true;
                        }
                        return false;
                    }
                }
        );
    }

    private EjbcaWS ejbcaWS;

    public static void main(String[] args) throws Exception {
        CaWS caWS = new CaWS();
        caWS.initEjbcaWs();
        caWS.create();
        caWS.findUser();
        caWS.revokeUser();
        caWS.findUser();

    }

    /**
     * 查询用户信息.
     */
    public void findUser() throws MalformedURLException, EjbcaException_Exception, IllegalQueryException_Exception, AuthorizationDeniedException_Exception, ApprovalException_Exception, UserDoesntFullfillEndEntityProfile_Exception, CADoesntExistsException_Exception, WaitingForApprovalException_Exception {
        UserMatch usermatch = new UserMatch();
        usermatch.setMatchwith(UserMatch.MATCH_WITH_EMAIL); //按EMAIL地址进行查询
        usermatch.setMatchtype(UserMatch.MATCH_TYPE_EQUALS);    //查询匹配方式
        usermatch.setMatchvalue("123@qq.com");
        List<UserDataVOWS> result = ejbcaWS.findUser(usermatch);
        System.out.println("result:" + result);

        for (UserDataVOWS ud : result) {
            System.out.println("==========================");
            System.out.println("userName:" + ud.getUsername());
            System.out.println("email:" + ud.getEmail());
            System.out.println("SubjectDN:" + ud.getSubjectDN());
            System.out.println("caName:" + ud.getCaName());
            System.out.println("==========================");
        }
    }

    /**
     * 初始化ws 接口服务.
     */
    public void initEjbcaWs() {

        CryptoProviderTools.installBCProvider();

        String urlstr = "https://172.17.2.248:8443/ejbca/ejbcaws/ejbcaws?wsdl";
        String fileName = "F:\\workspace\\caWS\\src\\superadmin.p12";
        String password = "ejbca";
        System.setProperty("javax.net.ssl.keyStore", fileName);
        System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");

        Provider tlsProvider = new TLSProvider();
        Security.addProvider(tlsProvider);
//        Security.addProvider(new BouncyCastleProvider());

        Security.setProperty("ssl.TrustManagerFactory.algorithm", "AcceptAll");
        System.setProperty("javax.net.ssl.keyStorePassword", password);
        try {
            KeyManagerFactory.getInstance("NewSunX509");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        Security.setProperty("ssl.KeyManagerFactory.algorithm", "NewSunX509");
        QName qname = new QName("http://ws.protocol.core.ejbca.org/", "EjbcaWSService");
        URL url = null;
        try {
            url = new URL(null, urlstr, new sun.net.www.protocol.http.Handler());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        EjbcaWSService service = new EjbcaWSService(url, qname);
        ejbcaWS = service.getEjbcaWSPort();

        String version = ejbcaWS.getEjbcaVersion();

        System.out.println("ejbcaWS init successfully. EJBCA Version is :" + version);
    }

    /**
     * 增加用户
     */
    public void create() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, NoSuchProviderException, IOException, WaitingForApprovalException_Exception, NotFoundException_Exception, AuthorizationDeniedException_Exception, ApprovalException_Exception, UserDoesntFullfillEndEntityProfile_Exception, CADoesntExistsException_Exception, EjbcaException_Exception, InvalidAlgorithmParameterException, SignatureException, InvalidKeyException, AlreadyRevokedException_Exception {
        String password = "123456";

        final UserDataVOWS userData = new UserDataVOWS();
        userData.setUsername("t_123");
        userData.setPassword(password); //如果模板指定自动生成密码，则不需要指定。
        userData.setClearPwd(false);
        userData.setSubjectDN("CN=t_123,OU=研发中心,O=qq.com,L=changchu,ST=jilin,C=china");
        userData.setCaName("ManagementCA");
        userData.setEmail("123@qq.com");
        userData.setSubjectAltName(null);
        userData.setStatus(UserDataVOWS.STATUS_NEW);
        userData.setTokenType(UserDataVOWS.TOKEN_TYPE_P12);
        userData.setEndEntityProfileName("EMPTY");
        userData.setCertificateProfileName("ENDUSER");
//        userData.setSendNotification(true);       //如果配置邮件发送，则可以设置增加用户时发送信息。
        ejbcaWS.editUser(userData);

        System.out.println("create user successfully.");

        System.out.println("write file");

        writeFile(userData, ejbcaWS);

        System.out.println("wirte file ok.");


        System.out.println("revoke user ok.");


    }

    /**
     * 注销用户
     * @throws NotFoundException_Exception
     * @throws AuthorizationDeniedException_Exception
     * @throws ApprovalException_Exception
     * @throws WaitingForApprovalException_Exception
     * @throws CADoesntExistsException_Exception
     * @throws AlreadyRevokedException_Exception
     * @throws EjbcaException_Exception
     */
    public void revokeUser() throws NotFoundException_Exception, AuthorizationDeniedException_Exception, ApprovalException_Exception, WaitingForApprovalException_Exception, CADoesntExistsException_Exception, AlreadyRevokedException_Exception, EjbcaException_Exception {
        ejbcaWS.revokeUser("t_123", 1, true);
    }

    /**
     * 生成证书
     */
    public void writeFile(UserDataVOWS user1, EjbcaWS ws) throws InvalidAlgorithmParameterException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, UserDoesntFullfillEndEntityProfile_Exception, AuthorizationDeniedException_Exception, ApprovalException_Exception, WaitingForApprovalException_Exception, NotFoundException_Exception, EjbcaException_Exception, InvalidKeyException, NoSuchProviderException, SignatureException, CADoesntExistsException_Exception {
        // For now, assume RSA and SHA1WithRSA.
        String strKeySpec = "1024";
        KeyPair keys = KeyTools.genKeys(strKeySpec,
                AlgorithmConstants.KEYALGORITHM_RSA);

        PKCS10CertificationRequest pkcs10 = new PKCS10CertificationRequest("SHA256withRSA", new X500Principal(
                user1.getSubjectDN()), keys.getPublic(), null, keys.getPrivate());

        CertificateResponse certenv = ws.certificateRequest(user1,
                new String(Base64.encode(pkcs10.getEncoded())),
                CertificateHelper.CERT_REQ_TYPE_PKCS10, null,
                CertificateHelper.RESPONSETYPE_CERTIFICATE);
//
        X509Certificate cert = certenv.getCertificate();
        java.security.KeyStore jks = java.security.KeyStore
                .getInstance(user1.getTokenType().equals("JKS") ? "JKS"
                        : "pkcs12");
        jks.load(null, user1.getPassword().toCharArray());

        java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory
                .getInstance("X.509");
        java.security.cert.Certificate cert1 = cf
                .generateCertificate(new ByteArrayInputStream(cert
                        .getEncoded()));

        java.security.cert.Certificate[] certs = new java.security.cert.Certificate[1];
        certs[0] = cert1;

        // Following logic used in EjbcaWS.java, the alias is the common
        // name, if present, and otherwise, is the username.
        String alias = CertTools.getPartFromDN(user1.getSubjectDN(),
                "CN");
        if (alias == null) {
            alias = user1.getUsername();
        }


        String strFileName = "c:\\temp\\test.p12";

        FileOutputStream out = new FileOutputStream(strFileName);

        // storing keystore
        java.security.PrivateKey ff = keys.getPrivate();

        jks.setKeyEntry(alias, ff, user1.getPassword().toCharArray(),
                certs);
        jks.store(out, user1.getPassword().toCharArray());
        out.close();
    }
}
